/*
 * Copyright (c) 2012 Sean Connelly
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var fs = require('fs');
var path = require('path');

function getAllTests(root_dir)
{
	var test_list = [];
	var files = fs.readdirSync(path.resolve(root_dir, 'test'));
	for (var i = 0; i < files.length; i++) // for each file in the ./test directory...
	{
		var file = path.resolve(root_dir, 'test', files[i]);
		if (fs.statSync(file).isDirectory()) // check to see if it's a directory itself
			test_list.push(path.basename(file)); // if so, add its name to test_list
	}
	test_list.sort();
	return test_list;
}

function getTestJs(root_dir, test_name)
{
	return path.resolve(root_dir, 'test', test_name, 'test.js');
}

function getValidTests(root_dir, test_list, invalidTestFn)
{
	var valid_test = [];
	for (var i = 0; i < test_list.length; i++)
	{
		var test_name = test_list[i];
		var test_js = getTestJs(root_dir, test_name);

		// check to see that the test is valid
		if (fs.existsSync(test_js))
			valid_test.push(test_name);
		else
			invalidTestFn(test_name);
	}
	return valid_test;
}

function executeTest(root_dir, test_name)
{
	var test_js = getTestJs(root_dir, test_name);
	var the_test = require(test_js);
	return the_test.run(root_dir, path.dirname(test_js), test_name);
}

function initTotals()
{
	return {
			pass: 0,
			fail: 0
		};
}

function reportTotals(totals)
{
	console.log('TOTAL PASS:  ' + totals.pass);
	console.log('TOTAL FAIL:  ' + totals.fail);
	console.log('-------------------');
	console.log('GRAND TOTAL: ' + (totals.pass + totals.fail));
}

function reportTestResults(test_name, results, totals)
{
	for (var i = 0; i < results.length; i++)
	{
		switch (results[i].result)
		{
		case 'pass':
			console.log('  pass  ' + test_name + ': ' + results[i].title);
			totals.pass++;
			break;
		case 'fail':
			console.log('! FAIL  ' + test_name + ': ' + results[i].title);
			totals.fail++;
			break;
		default:
			console.log('INVALID TEST: ' + test_name + '[' + i + '] =');
			console.log(results[i]);
			break;
		}
	}
}

//
// this is where execution begins
//
exports.run = function(root_dir, test_list) {

		// if requesting all tests, then get them based on directory names
		if (test_list === false)
			test_list = getAllTests(root_dir);

		if (test_list.length <= 0)
		{
			console.log('no tests');
			return;
		}

		// get a list of valid tests
		var valid_test = getValidTests(root_dir, test_list,
			function(invalid_test) { // called if getValidTests detects an invalid test
					console.log('invalid test: ' + invalid_test);
				});

		if (valid_test.length <= 0)
		{
			console.log('no valid tests');
			return;
		}

		// go through each test, execute, and report the results
		var totals = initTotals();
		for (var i = 0; i < valid_test.length; i++)
		{
			var results = executeTest(root_dir, valid_test[i]);
			reportTestResults(valid_test[i], results, totals);
		}
		console.log('');
		reportTotals(totals);
	};
